package net.oschina.esb.util;

import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射工具类
 *
 * @author Arvin
 * @time 2017/12/25 22:39
 */
public class ReflectUtil {

    /**
     * 查找指定类型的属性列表
     *
     * @param clazz     类名
     * @param fieldType 字段类型， 如果为空就返回所有的字段
     * @return 返回指定类型的属性列表，如果为空就返回所有的字段
     */
    public static List<Field> getNoneStaticDeclaredFields(Class<?> clazz, Class<?> fieldType) {
        if (null == clazz) {
            return new ArrayList<Field>();
        }
        Field[] declaredFields = clazz.getDeclaredFields();
        if (null != declaredFields && declaredFields.length > 0) {
            List<Field> fields = new ArrayList<Field>();
            for (Field field : declaredFields) {
                // 过滤静态属性
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                if (null == fieldType) {
                    fields.add(field);
                } else if (field.getType().equals(fieldType)) {
                    fields.add(field);
                }
            }
            return fields;
        }
        return new ArrayList<Field>();
    }

    /**
     * 获取指定类型所有的非静态属性字段
     *
     * @param clazz 类
     * @return
     */
    public static List<Field> getAllNoneStaticDeclaredFields(Class<?> clazz) {
        return getNoneStaticDeclaredFields(clazz, null);
    }

    /**
     * 获取字段的值
     */
    public static Object getFieldValue(Object obj, Field field) {
        if (null == obj || null == field) {
            return null;
        }
        field.setAccessible(true);
        try {
            return field.get(obj);
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    /**
     * 获取字段的值
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        if (null == obj || StringUtils.isBlank(fieldName)) {
            return null;
        }
        Field field = findDeclaredField(obj.getClass(), fieldName);
        if (null == field) {
            return null;
        }
        field.setAccessible(true);
        try {
            return field.get(obj);
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    /**
     * 搜索字段，包含私有的，从当前类开始搜索，如果当前类没有，继续往父类中查找，直到找到或到Object为止
     */
    public static Field findDeclaredField(Class<?> clazz, String fieldName) {
        if (null == clazz || StringUtils.isBlank(fieldName)) {
            return null;
        }
        for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
            try {
                return superClass.getDeclaredField(fieldName);
            } catch (NoSuchFieldException ignored) {
            }
        }
        return null;
    }

    /**
     * 设置属性的值
     */
    public static void setFieldValue(Object obj, Field field, Object value) {
        field.setAccessible(true);
        try {
            Class<?> type = field.getType();
            if (type.equals(Integer.class) || type.equals(int.class)) {
                field.set(obj, ((Number) value).intValue());
            } else if (type.equals(Long.class) || type.equals(long.class)) {
                field.set(obj, ((Number) value).longValue());
            } else {
                field.set(obj, value);
            }
        } catch (IllegalAccessException ignored) {
        }
    }

    /**
     * 设置属性的值
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        Field field = findDeclaredField(obj.getClass(), fieldName);
        if (null == field) {
            return;
        }
        field.setAccessible(true);
        try {
            field.set(obj, value);
        } catch (IllegalAccessException ignored) {
        }
    }

    /**
     * 获取指定类的指定类型的Annotation
     *
     * @param clazz           类
     * @param annotationClass annotation class
     * @param <A>             返回指定类型的Annotation
     * @return 如果不存在则返回null
     */
    public static <A extends Annotation> A getClassAnnotation(Class<?> clazz, Class<A> annotationClass) {
        AssertUtil.assertNotNull(clazz, "要获取Annotation的Class不能为空！");
        AssertUtil.assertNotNull(annotationClass, "要获取的Annotation类型不能为空！");
        return clazz.getAnnotation(annotationClass);
    }

    /**
     * 获取指定属性的指定类型的Annotation
     *
     * @param field           属性
     * @param annotationClass annotation class
     * @param <A>             返回指定类型的Annotation
     * @return 如果不存在则返回null
     */
    public static <A extends Annotation> A getFieldAnnotation(Field field, Class<A> annotationClass) {
        AssertUtil.assertNotNull(field, "要获取Annotation的Field不能为空！");
        AssertUtil.assertNotNull(annotationClass, "要获取的Annotation类型不能为空！");
        return field.getAnnotation(annotationClass);
    }
}
